﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;

namespace UrlRouting
{
    public class RouterEngine
    {
        private readonly static char[] slashChars = new char[] { '/', '\\' };
        private readonly static object lockObject = new object();
        private readonly static Dictionary<string, IsapiDomain> companies = new Dictionary<string, IsapiDomain>(StringComparer.OrdinalIgnoreCase);
        private readonly static List<string> imageFolders = new List<string>() { "asset", "imgsmall", "imgmedium", "imgcustom" };
        private readonly static List<string> passThruFolders = new List<string>() { "plp", "assets" };
        private readonly static Dictionary<string, int> locales = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
        {
            {"de-de", 1031},
            {"en-us", 1033},
            {"fr-fr", 1036},
            {"it-it", 1040},
            {"ja", 1041},
            {"ko", 1042},
            {"pl", 1045},
            {"pt-br", 1046},
            {"ro", 1048},
            {"ru", 1049},
            {"zh-cn", 2052},
            {"es-es", 3082},
        };

        public RouterEngine(IsapiDomain[] domains)
        {
            SetCompanyList(domains);
        }

        public void SetCompanyList(IsapiDomain[] domains)
        {
            lock (lockObject)
            {
                companies.Clear();
                foreach (var domain in domains)
                {
                    companies.Add(domain.Name, domain);
                }
            }
        }

        public bool Process(Uri url, out string path, out NameValueCollection headers)
        {
            path = null; headers = null;

            string company = url.Host.Split('.').FirstOrDefault();
            if (string.IsNullOrWhiteSpace(company)) return false;

            IsapiDomain isapiDomain;
            if (!companies.TryGetValue(company, out isapiDomain)) return false;

            string segment = null;
            int startIndex = 0;
            if (GetSegmentIndex(url, out startIndex))
            {
                segment = url.Segments[startIndex].TrimEnd(slashChars);
            }

            if (!string.IsNullOrWhiteSpace(segment)
                && passThruFolders.Any(i => i.Equals(segment, StringComparison.OrdinalIgnoreCase))) return false;

            headers = new NameValueCollection();
            int localeID;
            if (!string.IsNullOrWhiteSpace(segment)
                && locales.TryGetValue(segment, out localeID))
            {
                segment = (GetSegmentIndex(url, out startIndex, startIndex + 1))
                    ? url.Segments[startIndex].TrimEnd(slashChars) : null;
                headers.Add("plp-lid", localeID.ToString());
            }
            if (!string.IsNullOrWhiteSpace(segment)
                && imageFolders.Any(i => i.Equals(segment, StringComparison.OrdinalIgnoreCase)))
            {
                path = string.Format("/{0}/{1}{2}", isapiDomain.VD, isapiDomain.Name, GetPathAndQuery(url, startIndex));
            }
            else
            {
                path = "/plp" + GetPathAndQuery(url, startIndex);
            }

            headers.Add("plp-cid", isapiDomain.CID.ToString());
            headers.Add("plp-legacy", isapiDomain.Legacy.ToString());
            return true;
        }

        private bool GetSegmentIndex(Uri url, out int index, int startIndex = 0)
        {
            if (url.Segments != null)
            {
                for (int i = startIndex; i < url.Segments.Length; i++)
                {
                    if (url.Segments[i].Length == 1 && slashChars.Any(j => j.Equals(url.Segments[i][0]))) continue;
                    index = i;
                    return true;
                }
            }
            index = startIndex;
            return false;
        }

        private string GetPathAndQuery(Uri url, int startIndex = 0)
        {
            if (startIndex == 0) return url.PathAndQuery;
            var result = new StringBuilder();
            for (int i = startIndex; i < url.Segments.Length; i++)
            {
                result.Append(url.Segments[i]);
            }
            if (!string.IsNullOrWhiteSpace(url.Query))
            {
                result.Append(url.Query);
            }
            return slashChars[0].ToString() + result.ToString();
        }
    }
}
